export default class ScrollNav {

  private scrollContainer: HTMLElement = null
  private scrollItemList: HTMLElement[] = []
  private navItemList: HTMLElement[] = []
  private activeNavItemClass: string = ''
  private indexKey: string = ''
  private offset: number = 0
  private scrollTop: number = 0
  private option: ScrollNavConfig = null

  constructor(obj: ScrollNavConfig = {}) {
    this.option = {
      scrollContainer: obj.scrollContainer || '.scroll-container',
      scrollItem: obj.scrollItem || '.scroll-container .scroll-item',
      navItem: obj.navItem || '.nav .nav-item',
      activeNavItemClass: obj.activeNavItemClass || 'active',
      indexKey: obj.indexKey || 'value-key',
      offset: obj.offset || 10
    }

    // 滚动容器（overflow: auto）
    this.scrollContainer = document.querySelector(this.option.scrollContainer)

    // 滚动项
    this.scrollItemList = Array.from(document.querySelectorAll(this.option.scrollItem))

    // 导航项
    this.navItemList = Array.from(document.querySelectorAll(this.option.navItem))

    // 导航被激活的class
    this.activeNavItemClass = this.option.activeNavItemClass

    // 导航索引
    this.indexKey = this.option.indexKey

    // 偏移距离
    this.offset = this.option.offset

    // 滚动距离
    this.scrollTop = 0

    this.addEventListener()

    this.handleScroll() // 根据当前滚动距离激活默认菜单
  }

  // 添加事件监听
  public addEventListener() {
    if (this.scrollContainer) this.scrollContainer.addEventListener('scroll', this.handleScroll.bind(this))

    // 导航栏点击事件
    if (this.navItemList && this.navItemList.length) {
      this.navItemList.forEach((item, index) => {
        item.onclick = () => {
          this.handleNavClick(item, index)
        }
      })
    }
  }

  // 移除事件监听
  public removeEventListener() {
    if (this.scrollContainer) this.scrollContainer.removeEventListener('scroll', this.handleScroll.bind(this))
  }

  // 滚动事件
  private handleScroll() {
    const offset = this.scrollContainer.offsetTop

    this.scrollItemList.forEach((scrollItem, index) => {
      const offsetTop = this.scrollItemList[index].offsetTop - offset - this.scrollContainer.scrollTop
      const navItem = this.getNavItemByScrollItem(scrollItem, index)

      if (offsetTop < this.offset && navItem) {
        this.navItemList.forEach(item => {
          item.classList.remove(this.activeNavItemClass)
        })

        navItem.classList.add(this.activeNavItemClass)
      }
    })

    this.scrollTop = this.scrollContainer.scrollTop
  }

  // nav 点击事件
  private handleNavClick(item: HTMLElement, index: number) {
    const scrollItem = this.getScrollItemByNavItem(item, index)

    this.scrollToElement(scrollItem)

    setTimeout(() => {
      // 若滚动距离不够，已经到底
      if (!item.classList.contains(this.activeNavItemClass)) {
        this.navItemList.forEach(navItem => {
          navItem.classList.remove(this.activeNavItemClass)
        })
        item.classList.add(this.activeNavItemClass)
      }
    }, 50)
  }

  // 根据navItem查找对应的scrollItem
  private getScrollItemByNavItem(navItem: HTMLElement, index: number) {
    // 没有指定元素唯一值，则使用索引确定元素
    if (!this.indexKey) return this.scrollItemList[index]

    const indexKey = navItem.getAttribute(this.indexKey)
    if (!indexKey) return this.scrollItemList[index]

    // 指定了元素唯一值，则使用唯一值确定元素
    let scrollItem = null
    Array.prototype.forEach.call(this.scrollItemList, item => {
      if (item.getAttribute(this.indexKey) === indexKey) scrollItem = item
    })

    return scrollItem
  }

  // 根据scrollItem查找对应的navItem
  private getNavItemByScrollItem(scrollItem: HTMLElement, index: number) {
    // 没有指定元素唯一值，则使用索引确定元素
    if (!this.indexKey) return this.navItemList[index]

    const indexKey = scrollItem.getAttribute(this.indexKey)
    if (!indexKey) return this.navItemList[index]

    // 指定了元素唯一值，则使用唯一值确定元素
    let navItem = null
    Array.prototype.forEach.call(this.navItemList, item => {
      if (item.getAttribute(this.indexKey) === indexKey) navItem = item
    })

    return navItem
  }

  // 获取当前激活的导航
  public getActiveNavItem() {
    return document.querySelector(`${this.option.navItem}.${this.option.activeNavItemClass}`)
  }

  // 滚动至目标项
  public scrollToElement(scrollItem: HTMLElement) {
    if (!scrollItem) return

    this.scrollTop = scrollItem.offsetTop - this.scrollContainer.offsetTop
    this.scrollContainer.scrollTop = this.scrollTop
  }
}
